// const { node } = require("prop-types");
import Watcher from './watcher.js'

class Compile {
    constructor(el, vm){
        this.$el = document.querySelector(el); // 要遍历的宿主节点
        this.$vm = vm;

        if(this.$el){
            // 转换内部内容为片段fragment
            this.$fragment = this.node2Fragment(this.$el);
            // 执行编译
            this.compile(this.$fragment);
            // 将编译完的html结果追加至el
            this.$el.appendChild(this.$fragment);
        }
    }
    // 将宿主元素的代码片段拿出来遍历，这样做比较高校。
    node2Fragment(el) {
        const frag = document.createDocumentFragment();
        // 将el中的所有子元素搬家至frag中
        let child;
        while(child = el.firstChild){
            frag.appendChild(child)
        }
        return frag;
    }
    // 编译过程
    compile(el){
        const childNodes = el.childNodes;
        Array.from(childNodes).forEach(node => {
            if(this.isElement(node)){ // 处理元素
                
                // console.log('编译元素'+node.nodeName)
                // 查找 k-、@、:、
                const nodeAttrs = node.attributes;
                Array.from(nodeAttrs).forEach(attr => {
                    const attrName = attr.name;
                    const exp = attr.value;
                    if(this.isDirective(attrName)) { // 处理指令
                        // k-text
                        const dir = attrName.substring(2);
                        // 执行指令
                        this[dir] && this[dir](node, this.$vm, exp);
                    }
                    if(this.isEvent(attrName)){  // 处理事件
                        const dir = attrName.substring(1);
                        this.eventHandler(node, this.$vm, exp, dir)
                    }

                })

            } else if (this.isInterpolation(node)){ // 插值文本
                // console.log('编译文本'+node.textContent)
                this.compileText(node);
            }
            // 递归子节点
            if(node.childNodes && node.childNodes.length>0){
                this.compile(node)
            }
        })
    }
    compileText(node) {
        // console.log(`${RegExp.$1}`)
        // let groupName = RegExp.$1 // 捕获正则表达式匹配中的分组1
        // node.textContent = this.$vm.$data[groupName]; // 设置节点的textContent属性为data中的属性值，即完成了插值替换
       
        this.update(node, this.$vm, RegExp.$1, 'text')
    }

    // 更新函数 
    update(node, vm, exp, dir) {
        const updaterFn = this[dir+'Updater'];
        // 初始化
        updaterFn && updaterFn(node, vm[exp]);
        // 依赖收集
        new Watcher(vm, exp, function(value){
            updaterFn && updaterFn(node, value);
        })
    }

    text(node, vm, exp){
        this.update(node, vm, exp, 'text')
    }

    textUpdater(node, value) {
        node.textContent = value
    }

    // 双向绑定
    model(node, vm, exp){
        // 指定input value属性
        this.update(node, vm, exp, 'model');

        // 视图对模型响应
        node.addEventListener('input', e => {
            vm[exp] = e.target.value;
        });
    }

    modelUpdater(node, value){
        node.value = value;
    }

    html(node, vm, exp){
        this.update(node, vm, exp, 'html');
    }

    htmlUpdater(node, value){
        node.innerHTML = value;
    }

    eventHandler(node, vm, exp, dir) {
        // 取事件名
        let fn = vm.$options.methods && vm.$options.methods[exp];
        if(dir && fn) {
            node.addEventListener(dir, fn.bind(vm)); // 绑定事件监听
        }
    }

    isDirective(attr) {
        return attr.indexOf('k-') === 0;
    }
    isEvent(attr) {
        return attr.indexOf('@') === 0;
    }
    isElement(node) {
        return node.nodeType === 1;
    }
    isInterpolation(node){
        return node.nodeType === 3 && /\{\{(.*)\}\}/.test(node.textContent);
    }
}

export default Compile